﻿using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Filters;

using System.Diagnostics;

namespace Paragon.Logging
{
    [ConfigurationElementType(typeof(CustomLogFilterData))]
    public class SourceFilter : LogFilter, ILogFilter
    {
        public SourceFilter(NameValueCollection pairs) : base("SourceLogFilter")
        {            
            string sources = pairs["Sources"];
            if (!string.IsNullOrEmpty(sources))
                Sources = sources;

            string minValue = pairs["MinLevel"];
            if (!string.IsNullOrEmpty(minValue))
                MinLevel = (TraceEventType)Enum.Parse(typeof(TraceEventType), minValue, true);


            string maxValue = pairs["MaxLevel"];
            if (!string.IsNullOrEmpty(maxValue))
                MaxLevel = (TraceEventType)Enum.Parse(typeof(TraceEventType), maxValue, true);
        }

        public SourceFilter(string name) : base(name)
        {
            _sources = new List<string>();
        }

        public SourceFilter()
            : base(string.Empty)
        {
            _sources = new List<string>();
        }

        #region ILogFilter Members

        /// <summary>
        /// Checks the namespace of the calling class against the filter
        /// source using min and max severity level
        /// </summary>
        /// <seealso cref="System.Diagnostics.TraceEventType"/>
        /// <param name="log"></param>
        /// <returns></returns>
        public override bool Filter(Microsoft.Practices.EnterpriseLibrary.Logging.LogEntry log)
        {
            if (log.ExtendedProperties.ContainsKey(FILTER_NAME) && log.ExtendedProperties[FILTER_NAME] != null && !string.IsNullOrEmpty(log.ExtendedProperties[FILTER_NAME].ToString()))
            {
                return true;
            }
            else if(string.Equals(ALL_SOURCE, _originalSource))
            {
                return  TestSeverity(log.Severity);
            }
            else if (log.ExtendedProperties.ContainsKey(Logger.LOGGER_FULLNAME))
            {
                string fullname = log.ExtendedProperties[Logger.LOGGER_FULLNAME].ToString();

                int count = (from string filter in _sources
                             where  string.Equals(filter, fullname, StringComparison.CurrentCultureIgnoreCase) ||
                                    fullname.StartsWith(filter + ".", StringComparison.CurrentCultureIgnoreCase)
                             select filter).Count<string>();

                if(count > 0 && TestSeverity(log.Severity))
                {
                    log.ExtendedProperties[FILTER_NAME] = Name;
                    return true;
                }
            }            

            return true;
        }

        private bool TestSeverity(TraceEventType severity)
        {
            return  (!MinLevel.HasValue || severity >= MinLevel.Value) &&
                    (!MaxLevel.HasValue || severity <= MaxLevel.Value);
        }

        //public override string Name { get; set; }

        #endregion

        public string Sources
        {
            get
            {
                if (_sources != null)
                    return string.Join(",", _sources.ToArray());
                else
                    return null;
            }
            set
            {
                _originalSource = value;
                if (!string.IsNullOrEmpty(value))
                    _sources = new List<string>(value.Split(new char[] {','}));
            }
        }

        public TraceEventType? MinLevel { get; set; }
        public TraceEventType? MaxLevel { get; set; }

        private List<string> _sources;
        private string _originalSource;

        private const string ALL_SOURCE = "*";
        private const string FILTER_NAME = "FilterName";
    }
}
